
#include "../include/mystdafx.h"
#include "../os/os_sem.h"

#ifndef WIN32

typedef struct  
{
	sem_t hSem;
}os_semaphore_priv_t;

int os_sem_create(os_sem_t*s, int init_value)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) malloc(sizeof(os_semaphore_priv_t));
	if(!priv) return -1;
	s->pPriv = priv;

	if(sem_init(&priv->hSem, 0, init_value) < 0)
	{
		free(priv);
		s->pPriv = NULL;
		return -1;
	}

	return 0;
}

void os_sem_destroy(os_sem_t*s)
{
	if(s->pPriv)
	{
		os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
		sem_destroy(&priv->hSem);
		free(priv);
		s->pPriv = NULL;
	}
}

int os_sem_wait(os_sem_t*s)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
	if(!priv) return -1;

	if(sem_wait(&priv->hSem) < 0)
	{
		return -1;
	}
	return 0;
}

int os_sem_trywait(os_sem_t*s, int ms)
{
	struct timeval tv_now;
	struct timespec ts;
	int ns;

	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
	if(!priv) return -1;

	gettimeofday(&tv_now, NULL);

	ts.tv_sec = tv_now.tv_sec;
	ts.tv_nsec = tv_now.tv_usec * 1000;

	ns = ts.tv_nsec + (ms % 1000)  * 1000000;
	ts.tv_nsec = ns % 1000000000;
	ts.tv_sec += ns / 1000000000;
	ts.tv_sec += ms / 1000;

	if(sem_timedwait(&priv->hSem, &ts) != 0)
	{
		return -1;
	}

	return 0;;
}

void os_sem_pos(os_sem_t*s)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
	if(!priv) return;

	sem_post(&priv->hSem);
}

void os_sem_get_value(os_sem_t*s, int* value)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
	if(!priv) return;

	sem_getvalue(&priv->hSem, value);
}

#else

typedef struct  
{
	HANDLE hSem;
}os_semaphore_priv_t;

int os_sem_create(os_sem_t*s, int init_value)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) malloc(sizeof(os_semaphore_priv_t));
	if(!priv) return -1;
	s->pPriv = priv;

	priv->hSem = CreateSemaphore(NULL, init_value, 5000, NULL);
	if(priv->hSem == NULL)
	{
		free(priv);
		s->pPriv = NULL;
		return -1;
	}
	return 0;
}

void os_sem_destroy(os_sem_t*s)
{
	if(s->pPriv)
	{
		os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
		CloseHandle(priv->hSem);
		free(priv);
		s->pPriv = NULL;
	}
}

int os_sem_wait(os_sem_t*s)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*) s->pPriv;
	if(!priv) return -1;

	WaitForSingleObject(priv->hSem, INFINITE);
	return 0;
}

int os_sem_trywait(os_sem_t*s, int ms)
{
	DWORD  ret;
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*)  s->pPriv;
	if(!priv) return -1;

	ret = WaitForSingleObject(priv->hSem, ms);	
	if( ret == WAIT_OBJECT_0)
	{
		return 0; // success
	}
	if( ret == WAIT_TIMEOUT)
	{
		return -1; // timeout
	}
	return -1;
}

void os_sem_pos(os_sem_t*s)
{
	os_semaphore_priv_t* priv = (os_semaphore_priv_t*)  s->pPriv;
	if(!priv) return;

	ReleaseSemaphore(priv->hSem, 1, NULL);
}

void os_sem_get_value(os_sem_t*s, int* value)
{
	return ;
}

#endif


